package com.ruoyi.quartz.task;

import com.ruoyi.agent.domain.KwMachineAgent;
import com.ruoyi.agent.service.IKwMachineAgentService;
import com.ruoyi.attachments.domain.KwPackageInfo;
import com.ruoyi.attachments.service.IKwPackageInfoService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HostConstant;
import com.ruoyi.common.constant.LogConstant;
import com.ruoyi.common.constant.TaskConstant;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.LogUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.agent.AgentRequest;
import com.ruoyi.common.utils.agent.AgentRestUtil;
import com.ruoyi.common.utils.agent.AgentResult;
import com.ruoyi.common.utils.jsch.JschAuth;
import com.ruoyi.common.utils.jsch.JschResult;
import com.ruoyi.common.utils.jsch.JschUtil;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.credential.domain.KwCredentialAccess;
import com.ruoyi.credential.domain.KwUserCredential;
import com.ruoyi.credential.service.IKwCredentialAccessService;
import com.ruoyi.credential.service.IKwUserCredentialService;
import com.ruoyi.machine.domain.KwMachineInfo;
import com.ruoyi.machine.service.IKwMachineInfoService;
import com.ruoyi.task.domain.KwTaskInfo;
import com.ruoyi.task.domain.KwTaskLog;
import com.ruoyi.task.service.IKwTaskInfoService;
import com.ruoyi.task.service.IKwTaskLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * 定时任务调度测试
 * 
 * @author gonianer
 */
@Component("hostTaskHandler")
public class HostTaskHandler
{
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private IKwMachineInfoService machineInfoService;
    @Autowired
    private IKwUserCredentialService userCredentialService;
    @Autowired
    private IKwCredentialAccessService credentialAccessService;
    @Autowired
    private IKwMachineAgentService agentService;
    @Autowired
    private IKwPackageInfoService packageServie;
    @Autowired
    private IKwTaskInfoService taskInfoService;
    @Autowired
    private IKwTaskLogService taskLogService;

    @Async
    public void addHost(KwTaskInfo t,boolean isRetry){
        this.updateTaskStatus(t.getId(),TaskConstant.STATUS_RUNNING,isRetry);
        try {
            KwTaskInfo query = new KwTaskInfo();
            query.setpId(t.getId());
            List<KwTaskInfo> tasks = taskInfoService.selectKwTaskInfoList(query);
            KwMachineInfo machineInfo = machineInfoService.selectKwMachineInfoById(t.getJobId());
            if(machineInfo == null){
                throw new ServiceException("主机信息：id="+t.getJobId()+"不存在");
            }
            KwCredentialAccess access = new KwCredentialAccess();
            access.setUserId(Long.parseLong(machineInfo.getUpdateUser()));
            access.setTargetId(machineInfo.getId());
            List<KwCredentialAccess> accesses = credentialAccessService.selectKwCredentialAccessList(access);
            if(accesses==null || accesses.size()<1){
                throw new ServiceException("主机id="+t.getJobId()+"用户凭证信息不存在");
            }
            KwUserCredential credential = userCredentialService.selectKwUserPasswdById(accesses.get(0).getCredentialId());
            if (credential == null) {
                throw new ServiceException("主机用户凭证信息：id="+machineInfo.getCredentialId()+"不存在");
            }
            boolean flag = true;
            boolean retry = false;
            for(KwTaskInfo task : tasks){
                try {
                    if(isRetry && TaskConstant.STATUS_FAILED == task.getTaskStat()){
                        retry = true;
                    }
                    if(retry || !isRetry) {
                        this.updateTaskStatus(task.getId(), TaskConstant.STATUS_RUNNING,isRetry);
                        if ("checkHostCreat".equals(task.getTaskType()))
                            this.checkHostCreat(task, machineInfo, credential);
                        if ("syncHostInfo".equals(task.getTaskType()))
                            this.syncHostInfo(task, machineInfo, credential);
                        if ("createJwagentCredential".equals(task.getTaskType()))
                            this.createJwagentCredential(task);
                        if ("uploadJwagentSource".equals(task.getTaskType()))
                            this.uploadJwagentSource(task, machineInfo, credential);
                        if ("installJwagent".equals(task.getTaskType()))
                            this.installJwagent(task, machineInfo, credential);
                        if ("checkJwagentStatus".equals(task.getTaskType()))
                            this.checkJwagentStatus(task, machineInfo);
                        if ("updateHostStatus".equals(task.getTaskType()))
                            this.updateHostStatus(task, machineInfo);
                        this.updateTaskStatus(task.getId(), TaskConstant.STATUS_SUCCESS,isRetry);
                    }
                } catch (Exception e) {
                    logger.error("执行任务失败:" + e.getMessage());
                    this.updateTaskStatus(task.getId(), TaskConstant.STATUS_FAILED,isRetry);
                    this.updateTaskStatus(t.getId(), TaskConstant.STATUS_FAILED,isRetry);
                    flag = false;
                    break;
                }
            };
            if(flag) {
                this.updateTaskStatus(t.getId(), TaskConstant.STATUS_SUCCESS,isRetry);
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                        "添加主机任务完成：status="+HostConstant.STATUS_ONLINE);
            }
        }catch(Exception e){
            logger.error(e.getMessage());
            this.recordLog(t.getpId(),t.getId(), LogConstant.ERROR,e.getMessage());
            this.updateTaskStatus(t.getId(), TaskConstant.STATUS_FAILED,isRetry);
        }
    }

    @Async
    public void rollbackHost(Long taskId){
        boolean retry = false;
        KwTaskInfo t = taskInfoService.selectKwTaskInfoById(taskId.intValue());
        this.updateTaskStatus(t.getId(),TaskConstant.STATUS_RUNNING,retry);
        try {
            KwTaskInfo query = new KwTaskInfo();
            query.setpId(t.getId());
            List<KwTaskInfo> tasks = taskInfoService.selectKwTaskInfoList(query);
            KwMachineInfo machineInfo = machineInfoService.selectKwMachineInfoById(t.getJobId());
            if(machineInfo == null){
                throw new ServiceException("主机信息：id="+t.getJobId()+"不存在");
            }
            KwCredentialAccess access = new KwCredentialAccess();
            access.setUserId(Long.parseLong(machineInfo.getUpdateUser()));
            access.setTargetId(machineInfo.getId());
            List<KwCredentialAccess> accesses = credentialAccessService.selectKwCredentialAccessList(access);
            if(accesses==null || accesses.size()<1){
                throw new ServiceException("主机id="+t.getJobId()+"用户凭证信息不存在");
            }
            KwUserCredential credential = userCredentialService.selectKwUserPasswdById(accesses.get(0).getCredentialId());
            if (credential == null) {
                throw new ServiceException("主机用户凭证信息：id="+machineInfo.getCredentialId()+"不存在");
            }
            boolean flag = false;
            Collections.reverse(tasks);

            for(KwTaskInfo task : tasks){
                try {
                    if(TaskConstant.STATUS_FAILED == task.getTaskStat()) {
                        flag = true;
                    }
                    if(flag) {
                        this.updateTaskStatus(task.getId(), TaskConstant.STATUS_RUNNING,retry);
                        if ("checkHostCreat".equals(task.getTaskType()))
                            this.checkHostCreatRollback(task, machineInfo, credential);
                        if ("syncHostInfo".equals(task.getTaskType()))
                            this.syncHostInfoRollback(task, machineInfo, credential);
                        if ("createJwagentCredential".equals(task.getTaskType()))
                            this.createJwagentCredentialRollback(task);
                        if ("uploadJwagentSource".equals(task.getTaskType()))
                            this.uploadJwagentSourceRollback(task, machineInfo, credential);
                        if ("installJwagent".equals(task.getTaskType()))
                            this.installJwagentRollback(task, machineInfo, credential);
                        if ("checkJwagentStatus".equals(task.getTaskType()))
                            this.checkJwagentStatusRollback(task, machineInfo);
                        if ("updateHostStatus".equals(task.getTaskType()))
                            this.updateHostStatusRollback(task, machineInfo);

                        this.updateTaskStatus(task.getId(), TaskConstant.STATUS_WAIT,retry);
                    }
                } catch (Exception e) {
                    logger.error("执行任务失败:" + e.getMessage());
                    this.updateTaskStatus(task.getId(), TaskConstant.STATUS_FAILED,retry);
                    this.updateTaskStatus(t.getId(), TaskConstant.STATUS_FAILED,retry);
                    flag = false;
                    break;
                }
            };

            machineInfoService.deleteKwMachineInfoById(machineInfo.getId());

            this.updateTaskStatus(t.getId(), TaskConstant.STATUS_SUCCESS,retry);
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO, "放弃添加主机任务完成");
        }catch(Exception e){
            logger.error(e.getMessage());
            this.recordLog(t.getpId(),t.getId(), LogConstant.ERROR,e.getMessage());
            this.updateTaskStatus(t.getId(), TaskConstant.STATUS_SUCCESS,retry);
        }
    }

    @Async
    public void retryAddHost(Long taskId){
        KwTaskInfo t = taskInfoService.selectKwTaskInfoById(taskId.intValue());
        try {
            if(t == null){
                throw new ServiceException("任务新：id="+taskId+"不存在");
            }
            this.addHost(t,true);
        }catch(Exception e){
            logger.error(e.getMessage());
            this.recordLog(t.getpId(),t.getId(), LogConstant.ERROR,e.getMessage());
            this.updateTaskStatus(t.getId(), TaskConstant.STATUS_FAILED,true);
        }
    }
    /**
     * 更新任务状态
     * @param taskId
     * @param status
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void updateTaskStatus(Long taskId,Integer status,boolean retry){
        KwTaskInfo taskInfo = new KwTaskInfo();
        taskInfo.setId(taskId);
        taskInfo.setTaskStat(status);
        if(status.intValue() == TaskConstant.STATUS_RUNNING) {
            if(!retry)
                taskInfo.setStartTime(new Date());
            taskInfo.setEndTime(null);
        }else {
            taskInfo.setEndTime(new Date());
        }
        taskInfoService.updateKwTaskInfo(taskInfo);
    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void recordLog(Long pId,Long taskId,String level,String msg){
        KwTaskLog log = new KwTaskLog();
        log.setTaskId(taskId);
        log.setpId(pId);
        log.setLogLevel(level);
        msg = LogUtils.getLog(msg);
        log.setLogMsg(msg);
        taskLogService.insertKwTaskLog(log);
    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean checkHostCreat(KwTaskInfo t,KwMachineInfo machine,KwUserCredential credential){
        boolean flag = false;
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"开始执行预检查任务");
        //验证机器ssh连接
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                "ssh to :"+machine.getIp()+",port :"+machine.getSshPort()+" ,user: "+credential.getUsername());
        try {
            JschAuth jschAuth = new JschAuth(machine.getIp(),machine.getSshPort(),credential.getUsername(),credential.getSecret());
            JschUtil.testConnect(jschAuth);
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"ssh连接测试成功");
        } catch (Exception e) {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "test ssh failed:"+e.getMessage());
            throw e;
        }
        return flag;
    }
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean checkHostCreatRollback(KwTaskInfo t,KwMachineInfo machine,KwUserCredential credential){
        boolean flag = false;
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"任务回滚，无需操作");
        return flag;
    }


    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean syncHostInfo(KwTaskInfo t,KwMachineInfo machine,KwUserCredential credential) throws Exception {
        boolean flag = false;
        try {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "开始同步主机信息: "+JschUtil.COMMAND_SYS_INFO.replaceAll("_IP_",machine.getIp()));
            JschAuth jschAuth = new JschAuth(machine.getIp(),machine.getSshPort(),credential.getUsername(),credential.getSecret());
            JschResult sysInfo = JschUtil.execShell(jschAuth,JschUtil.COMMAND_SYS_INFO);
            if(sysInfo.getExitStatus()!=0)
                throw new ServiceException(sysInfo.getErrOutput());
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "获取主机信息结果: "+sysInfo.getMsgOutput());
            if(StringUtils.isNotEmpty(sysInfo.getMsgOutput())) {
                String[] info = sysInfo.getMsgOutput().split("\\n");
                if (info.length > 0)
                    machine.setHostName(info[0]);
                if (info.length > 1)
                    machine.setCpu(info[1]);
                if (info.length > 2)
                    machine.setOs(info[2]);
                if (info.length > 3)
                    machine.setNetCardName(info[3]);
            }
            machineInfoService.updateKwMachineInfo(machine);
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "更新主机信息成功");
        } catch (Exception e) {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "同步主机信息失败："+e.getMessage());
            throw e;
        }
        return flag;
    }
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean syncHostInfoRollback(KwTaskInfo t,KwMachineInfo machine,KwUserCredential credential) throws Exception {
        boolean flag = false;
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"任务回滚，无需操作");
        return flag;
    }


    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean createJwagentCredential(KwTaskInfo t){
        boolean flag = false;
        try {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "开始自动生成代理Http Basic认证信息");

            KwMachineAgent agent = new KwMachineAgent();
            agent.setMachineId(t.getJobId());
            List<KwMachineAgent> agents = agentService.selectKwMachineAgentList(agent);
            if(CollectionUtils.isEmpty(agents)){
                throw new ServiceException("检查主机：id="+t.getJobId()+"对应的jwagent代理信息不存在");
            }
            agent = agents.get(0);
            String passwd = UUID.randomUUID().toString();
            agent.setHttpUser(HostConstant.JWAGENT_USER);
            agent.setHttpPasswd(passwd);
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "生成jwagent Http Basic认证信息："
                            +HostConstant.JWAGENT_USER+"="+passwd);
            agentService.updateKwMachineAgent(agent);
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "生成jwagent Http Basic认证信息完成");
        } catch (Exception e) {
            throw e;
        }
        return flag;
    }
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean createJwagentCredentialRollback(KwTaskInfo t){
        boolean flag = false;
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"准备清理代理信息");
        KwMachineAgent agent = new KwMachineAgent();
        agent.setMachineId(t.getJobId());
        List<KwMachineAgent> agents = agentService.selectKwMachineAgentList(agent);
        if(CollectionUtils.isEmpty(agents)){
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "检查主机：id="+t.getJobId()+"对应的jwagent代理信息不存在");
            return flag;
        }
        agent = agents.get(0);
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"删除代理信息id="+agent.getId());
        agentService.deleteKwMachineAgentById(agent.getId());
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"清理代理信息完成");
        return flag;
    }


    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean uploadJwagentSource(KwTaskInfo t,KwMachineInfo machine,KwUserCredential credential) throws Exception {
        boolean flag = false;
        try {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "开始准备上传jwagent资源");
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "检查主机:id="+t.getJobId()+"对应代理配置信息");
            KwMachineAgent agent = agentService.selectKwMachineAgent(machine.getId());
            if(agent == null){
                throw new ServiceException("检查主机：id="+t.getJobId()+"对应的jwagent代理信息不存在");
            }
            String localPath = getLocalPath(t, agent);
            JschAuth jschAuth = new JschAuth(machine.getIp(),machine.getSshPort(),
                    credential.getUsername(),credential.getSecret());

            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "创建临时目录：mkdir -p "+HostConstant.JWAGENT_TEMP);
            JschResult result = JschUtil.execShell(jschAuth,"mkdir -p "+HostConstant.JWAGENT_TEMP);
            if(result.getExitStatus()!=0){
                throw new ServiceException("mkdir -p "+HostConstant.JWAGENT_TEMP+" 失败："+result.getErrOutput());
            }
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "开始上传jwagent资源:localPath="+localPath+",remotePath="+agent.getInstallHome());
            result = JschUtil.scpPackage(jschAuth,localPath,HostConstant.JWAGENT_TEMP);
            if(result.getExitStatus()!=0){
                throw new ServiceException("sftp上传文件失败："+result.getErrOutput());
            }
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "上传jwagent资源完成");
        } catch (Exception e) {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "上传jwagent资源失败："+e.getMessage());
            throw e;
        }
        return flag;
    }

    private String getLocalPath(KwTaskInfo t, KwMachineAgent agent) {
        String packageName = "jwagent-v1.0.0-x86.tar.gz";
        String localPath = RuoYiConfig.getPackagePath()+"/"+packageName;
        if(agent.getSoftwarePackageId()==null || agent.getSoftwarePackageId().intValue()==0){
            this.recordLog(t.getpId(), t.getId(),LogConstant.WARN,
                    "主机:id="+ t.getJobId()+"对应代理未指定安装包，使用默认代理");
        }else{
            KwPackageInfo filepackage = packageServie.selectKwPackageInfoById(agent.getSoftwarePackageId());
            if(filepackage==null){
                this.recordLog(t.getpId(), t.getId(),LogConstant.WARN,
                        "主机:id="+ t.getJobId()+"对应代理未指定安装包，将使用默认代理");
            }else{
                String filePath = RuoYiConfig.getProfile()+filepackage.getPackagePath();
                File file = new File(filePath);
                if(!file.exists()){
                    this.recordLog(t.getpId(), t.getId(),LogConstant.WARN,
                            "主机:id="+ t.getJobId()+"对应代理安装包不存在，将使用默认代理");
                }else{
                    localPath = filePath;
                }
            }
        }
        return localPath;
    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean uploadJwagentSourceRollback(KwTaskInfo t,KwMachineInfo machine,KwUserCredential credential) throws Exception {
        boolean flag = false;
        try {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "开始准备清理jwagent资源");
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "检查主机:id="+t.getJobId()+"对应代理配置信息");
            KwMachineAgent agent = agentService.selectKwMachineAgent(machine.getId());
            if(agent == null){
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                        "检查主机：id="+t.getJobId()+"对应的jwagent代理信息不存在");
                return flag;
            }
            JschAuth jschAuth = new JschAuth(machine.getIp(),machine.getSshPort(),
                    credential.getUsername(),credential.getSecret());
            String packageName = "jwagent-v1.0.0-x86.tar.gz";
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "删除临时目录资源：rm -rf "+HostConstant.JWAGENT_TEMP+"/"+packageName);
            JschResult result = JschUtil.execShell(jschAuth,"rm -rf "+HostConstant.JWAGENT_TEMP);
            if(result.getExitStatus()!=0){
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                        "rm -rf "+HostConstant.JWAGENT_TEMP+"/"+packageName+" 失败："+result.getErrOutput());
                return flag;
            }
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "清理jwagent资源完成");
        } catch (Exception e) {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "清理jwagent资源失败："+e.getMessage());
        }
        return flag;
    }


    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean installJwagent(KwTaskInfo t,KwMachineInfo machine,KwUserCredential credential) throws Exception {
        boolean flag = false;
        try {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "开始准备安装jwagent");
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "检查主机:id="+t.getJobId()+"对应代理配置信息");
            KwMachineAgent agent = agentService.selectKwMachineAgent(machine.getId());
            if(agent == null){
                throw new ServiceException("检查主机：id="+t.getJobId()+"对应的jwagent代理信息不存在");
            }
            JschAuth jschAuth = new JschAuth(machine.getIp(),machine.getSshPort(),
                    credential.getUsername(),credential.getSecret());
            String mkHome = "mkdir -p "+agent.getInstallHome();
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "创建jwagent安装目录："+mkHome);
            JschResult result = JschUtil.execShell(jschAuth,mkHome);
            if(result.getExitStatus()!=0){
                throw new ServiceException(mkHome+" 失败："+result.getErrOutput());
            }
            //解压资源
            String localPath = getLocalPath(t, agent);
            String packageName = localPath.substring(localPath.lastIndexOf("/"+1));
            String packageExt = packageName.substring(packageName.lastIndexOf("."+1));
            String resoucePath = HostConstant.JWAGENT_TEMP+"/"+packageName;
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "开始解压资源:resoucePath="
                            +resoucePath+",installHome="+agent.getInstallHome());
            String command = null;
            if(Constants.PACKAGE_TAR.equals(packageExt)) {
                command = "cd " + agent.getInstallHome() + " && tar -zxf " + resoucePath + " --strip-components=1";
            }else{
                command = "cd " + agent.getInstallHome() + " && rpm2cpio " + resoucePath + " | cpio -di";
            }
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO, command);
            result = JschUtil.execShell(jschAuth,command);
            if(result.getExitStatus()!=0){
                throw new ServiceException("解压资源文件失败："+result.getErrOutput());
            }
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO, "资源解压完成");
            //设置代理配置文件
            String httpBasicPath = "~/" + agent.getInstallHome() + "/conf/config_properties/basic_auth.yaml";
            String agentPortPath = "~/" + agent.getInstallHome() + "/conf/config_properties/common_meta.yaml";
            String agentIpPath = "~/" + agent.getInstallHome() + "/conf/config_properties/monagent_pipeline.yaml";
            command = "sed -i 's/jwagentUsername/"+agent.getHttpUser()+"/g;s/jwagentPassword/"+agent.getHttpPasswd()+"/g' "+httpBasicPath
                    + " && sed -i 's/8088/"+agent.getPort()+"/g' "+agentPortPath
                    + " && sed -i 's/monagentHostIp/"+machine.getIp()+"/g' "+agentIpPath;
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO, "更新代理配置文件："+command);
            result = JschUtil.execShell(jschAuth,command);
            if(result.getExitStatus()!=0){
                throw new ServiceException("更新代理配置文件失败："+result.getErrOutput());
            }
            //启动进程
            command = "pwd";
            result = JschUtil.execShell(jschAuth,command);
            if(result.getExitStatus()!=0){
                throw new ServiceException("执行pwd命令失败："+result.getErrOutput());
            }
            String userHome = result.getMsgOutput();
            command = userHome+"/"+agent.getInstallHome()+"/bin/jwagent -c "
                    +userHome+"/"+agent.getInstallHome()+"/conf/jwagent.yaml";
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO, "启动代理："+command);
            agent.setCommandArgs(command);
            result = JschUtil.execShell(jschAuth,command);
            if(result.getExitStatus()!=0){
                throw new ServiceException("启动代理失败："+result.getErrOutput());
            }
            //获取代理进程信息
            command="pgrep -af \"jwagent\" |head -1|awk '{print $1}'";
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO, "获取jwagent进程信息："+command);

            if(result.getExitStatus()!=0){
                throw new ServiceException("获取代理进程id失败："+result.getErrOutput());
            }
            String pid = result.getErrOutput();
            agent.setPid(Long.parseLong(pid));
            agent.setUpTime(new Date().getTime());
            agent.setLastActiveTime(new Date());
            agent.setStatus(HostConstant.JWAGENT_AVAILABLE);
            agentService.updateKwMachineAgent(agent);
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "安装jwagent代理完成");
        } catch (Exception e) {
            this.recordLog(t.getpId(),t.getId(),LogConstant.ERROR,
                    "安装jwagent代理失败："+e.getMessage());
            throw e;
        }
        return flag;
    }
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean installJwagentRollback(KwTaskInfo t,KwMachineInfo machine,KwUserCredential credential) throws Exception {
        boolean flag = false;
        try {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "开始准备卸载jwagent代理");
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "检查主机:id="+t.getJobId()+"对应代理配置信息");
            KwMachineAgent agent = new KwMachineAgent();
            agent.setMachineId(t.getJobId());
            List<KwMachineAgent> agents = agentService.selectKwMachineAgentList(agent);
            if(CollectionUtils.isEmpty(agents)){
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                        "检查主机：id="+t.getJobId()+"对应的jwagent代理信息不存在");
                return flag;
            }
            agent = agents.get(0);
            JschAuth jschAuth = new JschAuth(machine.getIp(),machine.getSshPort(),
                    credential.getUsername(),credential.getSecret());

            String command="pgrep -af \"jwagent\" |head -1|awk '{print $1}'|xargs --no-run-if-empty kill -9";
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO, "结束jwagent进程信息："+command);
            JschResult result = JschUtil.execShell(jschAuth,command);
            if(result.getExitStatus()!=0){
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                        "结束代理进程id失败："+result.getErrOutput());
                return flag;
            }
            String rmHome = "rm -rf "+agent.getInstallHome();
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "删除jwagent安装目录："+rmHome);

            result = JschUtil.execShell(jschAuth,rmHome);
            if(result.getExitStatus()!=0){
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                        rmHome+" 失败："+result.getErrOutput());
                return flag;
            }

            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "卸载jwagent代理完成");
        } catch (Exception e) {
            this.recordLog(t.getpId(),t.getId(),LogConstant.ERROR,
                    "卸载jwagent代理失败："+e.getMessage());
        }
        return flag;
    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean checkJwagentStatus(KwTaskInfo t,KwMachineInfo machine){
        boolean flag = false;
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"检查机器:"+machine.getIp()+"，jwagent状态");
        KwMachineAgent agent = agentService.selectKwMachineAgent(machine.getId());
        AgentRequest request = new AgentRequest(machine.getIp(),agent.getPort(),agent.getHttpUser(),agent.getHttpPasswd());
        request.setCommand("date");
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                "post "+machine.getIp()+" for date exec ");
        AgentResult result = AgentRestUtil.postAgentCommand(request);
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                "post "+machine.getIp()+" for date exec result: retcode:" +result.getData().getRetcode()
                        +",stdout:"+result.getData().getStdout()
                        +",stderr:"+result.getData().getStderr()
        );
        if(result.getData().getRetcode()!=0){
            throw new ServiceException("机器:"+machine.getIp()+"，jwagent状态异常");
        }
        return flag;
    }
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean checkJwagentStatusRollback(KwTaskInfo t,KwMachineInfo machine){
        boolean flag = false;
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"任务回滚，无需操作");
        return flag;
    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean updateHostStatus(KwTaskInfo t,KwMachineInfo machine){
        boolean flag = false;
        machine.setStatus(HostConstant.STATUS_ONLINE);
        machineInfoService.updateKwMachineInfo(machine);
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                "更新主机状态："+HostConstant.STATUS_ONLINE);
        return flag;
    }
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean updateHostStatusRollback(KwTaskInfo t,KwMachineInfo machine){
        boolean flag = false;
        this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"任务回滚，无需操作");
        return flag;
    }


    @Async
    public void delHost(KwTaskInfo t,boolean isRetry){
        this.updateTaskStatus(t.getId(),TaskConstant.STATUS_RUNNING,isRetry);
        try {
            KwTaskInfo query = new KwTaskInfo();
            query.setpId(t.getId());
            List<KwTaskInfo> tasks = taskInfoService.selectKwTaskInfoList(query);
            KwMachineInfo machineInfo = machineInfoService.selectKwMachineInfoById(t.getJobId());
            if(machineInfo == null){
                throw new ServiceException("主机信息：id="+t.getJobId()+"不存在");
            }
            KwCredentialAccess access = new KwCredentialAccess();
            access.setUserId(Long.parseLong(machineInfo.getUpdateUser()));
            access.setTargetId(machineInfo.getId());
            List<KwCredentialAccess> accesses = credentialAccessService.selectKwCredentialAccessList(access);
            if(accesses==null || accesses.size()<1){
                throw new ServiceException("主机id="+t.getJobId()+"用户凭证信息不存在");
            }
            KwUserCredential credential = userCredentialService.selectKwUserPasswdById(accesses.get(0).getCredentialId());
            if (credential == null) {
                throw new ServiceException("主机用户凭证信息：id="+machineInfo.getCredentialId()+"不存在");
            }
            boolean flag = true;
            boolean retry = false;
            for(KwTaskInfo task : tasks){
                try {
                    if(isRetry && TaskConstant.STATUS_FAILED == task.getTaskStat()){
                        retry = true;
                    }
                    if(retry || !isRetry) {
                        this.updateTaskStatus(task.getId(), TaskConstant.STATUS_RUNNING,isRetry);
                        if ("checkHostDelete".equals(task.getTaskType()))
                            this.checkHostCreat(task, machineInfo, credential);
                        if ("uninstallJwagentService".equals(task.getTaskType()))
                            this.uninstallJwagentService(task, machineInfo,credential);
                        if ("deleteHostInfo".equals(task.getTaskType()))
                            this.deleteHostInfo(task, machineInfo, credential);
                        this.updateTaskStatus(task.getId(), TaskConstant.STATUS_SUCCESS,isRetry);
                    }
                } catch (Exception e) {
                    logger.error("执行任务失败:" + e.getMessage());
                    this.updateTaskStatus(task.getId(), TaskConstant.STATUS_FAILED,isRetry);
                    this.updateTaskStatus(t.getId(), TaskConstant.STATUS_FAILED,isRetry);
                    flag = false;
                    break;
                }
            };
            if(flag) {
                this.updateTaskStatus(t.getId(), TaskConstant.STATUS_SUCCESS,isRetry);
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                        "删除主机任务完成：status="+HostConstant.STATUS_DELETED);
            }
        }catch(Exception e){
            logger.error(e.getMessage());
            this.recordLog(t.getpId(),t.getId(), LogConstant.ERROR,e.getMessage());
            this.updateTaskStatus(t.getId(), TaskConstant.STATUS_FAILED,isRetry);
        }
    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean uninstallJwagentService(KwTaskInfo t,KwMachineInfo machine,KwUserCredential credential) throws Exception {
        boolean flag = false;
        try {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "开始准备卸载jwagent代理");
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "检查主机:id="+t.getJobId()+"对应代理配置信息");
            KwMachineAgent agent = new KwMachineAgent();
            agent.setMachineId(t.getJobId());
            List<KwMachineAgent> agents = agentService.selectKwMachineAgentList(agent);
            if(CollectionUtils.isEmpty(agents)){
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                        "检查主机：id="+t.getJobId()+"对应的jwagent代理信息不存在");
                return flag;
            }
            agent = agents.get(0);
            JschAuth jschAuth = new JschAuth(machine.getIp(),machine.getSshPort(),
                    credential.getUsername(),credential.getSecret());

            String command="pgrep -af \"jwagent\" |head -1|awk '{print $1}'|xargs --no-run-if-empty kill -9";
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO, "结束jwagent进程信息："+command);
            JschResult result = JschUtil.execShell(jschAuth,command);
            if(result.getExitStatus()!=0){
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                        "结束代理进程id失败："+result.getErrOutput());
            }
            String rmHome = "rm -rf "+agent.getInstallHome();
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "删除jwagent安装目录："+rmHome);

            result = JschUtil.execShell(jschAuth,rmHome);
            if(result.getExitStatus()!=0){
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                        rmHome+" 失败："+result.getErrOutput());
            }

            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,
                    "卸载jwagent代理完成");
        } catch (Exception e) {
            this.recordLog(t.getpId(),t.getId(),LogConstant.ERROR,
                    "卸载jwagent代理失败："+e.getMessage());
        }
        return flag;
    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public boolean deleteHostInfo(KwTaskInfo t,KwMachineInfo machine,KwUserCredential credential) throws Exception {
        boolean flag = false;
        try {
            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"开始准备删除主机信息");
            KwMachineAgent agent = new KwMachineAgent();
            agent.setMachineId(t.getJobId());
            List<KwMachineAgent> agents = agentService.selectKwMachineAgentList(agent);
            if(CollectionUtils.isEmpty(agents)){
                this.recordLog(t.getpId(),t.getId(),LogConstant.WARN,"检查主机：id="+t.getJobId()+"对应的jwagent代理信息不存在");
            }else{
                agent = agents.get(0);
                try {
                    agentService.deleteKwMachineAgentById(agent.getId());
                    this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"清理代理信息：id="+agent.getId()+"完成");
                } catch (Exception e) {
                    this.recordLog(t.getpId(),t.getId(),LogConstant.WARN,"清理代理信息：id="+agent.getId()+"异常:"+e.getMessage());
                }
            }
            try {
                machineInfoService.deleteKwMachineInfoById(machine.getId());
                this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"清理主机信息：id="+machine.getId()+"完成");
            } catch (Exception e) {
                this.recordLog(t.getpId(),t.getId(),LogConstant.WARN,"清理主机信息：id="+machine.getId()+"异常:"+e.getMessage());
            }

            this.recordLog(t.getpId(),t.getId(),LogConstant.INFO,"删除主机信息完成");
        } catch (Exception e) {
            this.recordLog(t.getpId(),t.getId(),LogConstant.ERROR,"删除主机信息失败："+e.getMessage());
        }
        return flag;
    }

}
